﻿#region [ License information          ]
/* ************************************************************
 *
 * Copyright (c) Bjørn Bouet Smith, 2012
 *
 * This source code is subject to terms and conditions of 
 * Microsoft Public License (Ms-PL).
 * 
 * A copy of the license can be found in the license.txt
 * file at the root of this distribution. If you can not 
 * locate the License, please send an email to bjornsmith@gmail.com
 * 
 * By using this source code in any fashion, you are 
 * agreeing to be bound by the terms of the Microsoft 
 * Public License.
 *
 * You must not remove this notice, or any other, from this
 * software.
 *
 * ************************************************************/
#endregion

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text.RegularExpressions;
using Smith.BuildExtensions.Logging;

namespace Smith.BuildExtensions.ConfigurationTransformation
{
    /// <summary>
    /// Class that transform configuration templates into configuration files.
    /// </summary>
    public class ConfigTransformer : IConfigTransformer
    {
        private readonly IConfigReader configReader;

        private readonly IKeyReader keyReader;
        
        private readonly IValueSelector selector;

        /// <summary>
        /// Initializes a new instance of the <see cref="ConfigTransformer"/> class.
        /// </summary>
        /// <param name="configReader">The config reader.</param>
        /// <param name="keyReader">The key reader.</param>
        /// <param name="selector">The selector to select the correct value.</param>
        public ConfigTransformer(
            IConfigReader configReader, 
            IKeyReader keyReader, 
            IValueSelector selector)
        {
            this.configReader = configReader;
            this.keyReader = keyReader;
            this.selector = selector;
        }

        /// <summary>
        /// Transforms the configuration and returns the transformed configuration as a string.
        /// </summary>
        /// <returns>The transformed configuration.</returns>
        public string TransformConfiguration()
        {
            const int MaxRecursions = 10;

            int recursion = 0;
            
            string baseAppSettings = configReader.GetConfigurationTemplate();

            ICollection<string> remaingKeys = keyReader.GetKeys(baseAppSettings);

            while (remaingKeys.Count > 0 && recursion < MaxRecursions)
            {
                foreach (string key in remaingKeys)
                {
                    string newValue = selector.SelectValue(key);

                    if(newValue==null)
                    {
                        continue;
                    }

                    baseAppSettings = ReplaceMatches(baseAppSettings, key, newValue);
                }

                recursion += 1;
                remaingKeys = keyReader.GetKeys(baseAppSettings);
            }

            return baseAppSettings;
        }

        private static string ReplaceMatches(string baseAppSettings, string keyName, string value)
        {
            return KeyReader.KeyRegex.Replace(baseAppSettings, match =>
            {
                Group g = match.Groups["Key"];
                if (g.Value.Equals(keyName))
                {
                    return value;
                }

                return match.Value;
            });
        }
    }
}
